package com.bihu.bihudemo.auth.filter;


import com.bihu.bihudemo.auth.compoent.CustomAuthenticationFailureHandler;
import com.bihu.bihudemo.auth.compoent.JwtTokenUtil;
import com.bihu.bihudemo.entity.vo.CaptchVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;
import org.thymeleaf.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * 自定义拦截器，设置token持久化登录状态，OncePerRequestFilter该过滤器只会被过滤一次
 */

@Controller
public class MyOncePerRequestFilter extends OncePerRequestFilter {

    private String header = "Authorization";


    @Resource
    JwtTokenUtil jwtTokenUtil;

    // 自定义认证失败处理器
    @Resource
    CustomAuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {


        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", origin);
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Allow-Headers", "Origin,Content-Type,Accept,token,X-Requested-With");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        String headerToken = request.getHeader(header);
        System.out.println("headerToken = " + headerToken);
        System.out.println("request getMethod = " + request.getMethod());

        //1要是用户是携带token请求的，那么说明用户之前已经登陆系统。
        //2 那么在校验过token合法的前提下，应该告诉springSecurity 这个用户是在登录状态的
        //3 没有登陆过，就不用做拦截，直接交给用户名密码校验的拦截器
        if (!StringUtils.isEmpty(headerToken)) {
            //postMan测试时，自动加入的前缀，要去掉。
            String token = headerToken.replace("Bearer", "").trim();
            System.out.println("token = " + token);

            //校验令牌是否过期
            boolean check = false;
            try {
                check = this.jwtTokenUtil.isTokenExpired(token);
            } catch (Exception e) {
                new Throwable("令牌已过期，请重新登录。" + e.getMessage());
            }

            //要没有过期，就检查用户是否存在，令牌是否有效,全部完成之后告诉springSecurity该用户已经登录过，且信息合法
            if (!check) {
                String username = jwtTokenUtil.getUsernameFromToken(token);
                //判断用户不为空，且SecurityContextHolder授权信息还是空的
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                    //验证令牌有效性
                    boolean validata = false;
                    try {
                        validata = jwtTokenUtil.validateToken(token, userDetails);
                    } catch (Exception e) {
                        new Throwable("验证token无效:" + e.getMessage());
                    }
                    //令牌有效
                    if (validata) {
                        // 将用户信息存入 authentication，方便后续校验
                        UsernamePasswordAuthenticationToken authentication =
                                new UsernamePasswordAuthenticationToken(
                                        userDetails,
                                        null,
                                        userDetails.getAuthorities()
                                );
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        // 将 authentication 存入 安全框架上下文，方便后续获取用户信息（就是设置已经登录）
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            }
        }
        filterChain.doFilter(request, response);

    }



}
